﻿Imports System.IO
Imports System.Xml
Imports System.Text
Imports System.Xml.Xsl
Imports System.Xml.XPath
Imports System.Security.Cryptography
Imports System.Security.Cryptography.X509Certificates
Imports System.Xml.Serialization
Imports System.Xml.Schema
Imports System.Threading
Imports System.Globalization
Imports WSEntidades


Public Class csUtilsCFD
    ''' <summary>
    ''' Transforma la clase IEDU a un XMLElement
    ''' </summary>
    ''' <param name="objetoIedu">objeto clase Iedu</param>
    ''' <param name="pMsgError">mensaje de eerror</param>
    ''' <returns>XMLElement on Error Nothing</returns>
    ''' <remarks></remarks>
    Public Function formaXmlIEDU(ByVal objetoIedu As instEducativas, _
                                        ByRef pMsgError As String) As XmlElement
        Thread.CurrentThread.CurrentCulture = New CultureInfo("es-MX", False)
        Try
            Dim memory_stream As New MemoryStream()
            Dim xmlNameSpace As XmlSerializerNamespaces = New XmlSerializerNamespaces()
            xmlNameSpace.Add("iedu", "http://www.sat.gob.mx/iedu")

            Dim xmlTextWriter As XmlTextWriter = New XmlTextWriter(memory_stream, Encoding.UTF8)
            Dim preFactXml As XmlDocument = New XmlDocument()
            xmlTextWriter.Formatting = Formatting.Indented
            xmlTextWriter.Indentation = 4
            Dim xs As XmlSerializer = New XmlSerializer(GetType(instEducativas))

            xs.Serialize(xmlTextWriter, objetoIedu, xmlNameSpace)
            Dim stream_reader As New StreamReader(memory_stream)
            memory_stream.Seek(0, SeekOrigin.Begin)
            'Se carga el documento xml en 'preFactXml'
            preFactXml.LoadXml(stream_reader.ReadToEnd())
            xmlTextWriter.Close()
            Return preFactXml.DocumentElement
        Catch ex As Exception
            Return Nothing
        End Try

    End Function

    Public Function formaXmlTerceros(ByVal objetoTerceros As Terceros.PorCuentadeTerceros, _
                                        ByRef pMsgError As String) As XmlElement
        Thread.CurrentThread.CurrentCulture = New CultureInfo("es-MX", False)
        Try
            Dim memory_stream As New MemoryStream()
            Dim xmlNameSpace As XmlSerializerNamespaces = New XmlSerializerNamespaces()
            xmlNameSpace.Add("terceros", "http://www.sat.gob.mx/terceros")

            Dim xmlTextWriter As XmlTextWriter = New XmlTextWriter(memory_stream, Encoding.UTF8)
            Dim preFactXml As XmlDocument = New XmlDocument()
            xmlTextWriter.Formatting = Formatting.Indented
            xmlTextWriter.Indentation = 4
            Dim xs As XmlSerializer = New XmlSerializer(GetType(Terceros.PorCuentadeTerceros))
            xs.Serialize(xmlTextWriter, objetoTerceros, xmlNameSpace)
            Dim stream_reader As New StreamReader(memory_stream)
            memory_stream.Seek(0, SeekOrigin.Begin)
            'Se carga el documento xml en 'preFactXml'
            preFactXml.LoadXml(stream_reader.ReadToEnd())
            xmlTextWriter.Close()
            Return preFactXml.DocumentElement
        Catch ex As Exception
            Return Nothing
        End Try
    End Function

    Public Function formaXmlVehiculos(ByVal objetoVehiculos As VentaVehiculos.VentaVehiculos, _
                                        ByRef pMsgError As String) As XmlElement
        Thread.CurrentThread.CurrentCulture = New CultureInfo("es-MX", False)
        Try
            Dim memory_stream As New MemoryStream()
            Dim xmlNameSpace As XmlSerializerNamespaces = New XmlSerializerNamespaces()
            xmlNameSpace.Add("ventavehiculos", "http://www.sat.gob.mx/ventavehiculos")

            Dim xmlTextWriter As XmlTextWriter = New XmlTextWriter(memory_stream, Encoding.UTF8)
            Dim preFactXml As XmlDocument = New XmlDocument()
            xmlTextWriter.Formatting = Formatting.Indented
            xmlTextWriter.Indentation = 4
            Dim xs As XmlSerializer = New XmlSerializer(GetType(VentaVehiculos.VentaVehiculos))
            xs.Serialize(xmlTextWriter, objetoVehiculos, xmlNameSpace)
            Dim stream_reader As New StreamReader(memory_stream)
            memory_stream.Seek(0, SeekOrigin.Begin)
            'Se carga el documento xml en 'preFactXml'
            preFactXml.LoadXml(stream_reader.ReadToEnd())
            xmlTextWriter.Close()
            Return preFactXml.DocumentElement
        Catch ex As Exception
            Return Nothing
        End Try

    End Function

    ''' <summary>
    ''' Analiza el CFD para ver si es válido comparado con el XSLT del SAT
    ''' Si contiene un nodo CadenaOriginal la remueve de <c>pXml</c>
    ''' </summary>
    ''' <param name="pXml">Por referencia. Es la respuesta del Servicio Web de tipo XmlDocumento</param>
    ''' <param name="pRutaLayout">Ruta del Layout</param>
    ''' <returns>True: Si el CFD es válido
    ''' False: Si no es válido</returns>
    ''' <remarks>Obtiene la Cadena original mediante el XSLT.  
    ''' Si <c>pXml</c> contiene un nodo Cadena Original lo remueve y lo compara con la cadena generada
    ''' </remarks>
    Public Shared Function esCFDValido(ByRef pXml As XmlDocument, ByVal pRutaLayout As String) As Boolean
        Try
            Dim valido As Boolean = False
            Dim strCadOrig As String = "" 'csUtilsCFD.getCadenaOriginalFromCFD(pXml)
            If (strCadOrig <> "") Then
                Dim nodeList As XmlNodeList
                nodeList = pXml.GetElementsByTagName("Cadena")
                If (nodeList.Count = 1) Then
                    Dim cadenaOrigSifei As String = nodeList(0).Attributes.GetNamedItem("CadenaOriginal").Value
                    'REMUEVE EL NODO CADENAORIGINAL
                    Dim nodoPadreLs As XmlNodeList = pXml.GetElementsByTagName(nodeList(0).ParentNode.Name)
                    Dim nodoPadre As XmlNode
                    nodoPadre = nodoPadreLs.Item(0)
                    nodoPadre.RemoveChild(nodeList(0))
                    If (strCadOrig = cadenaOrigSifei) Then
                        valido = True
                    Else
                        valido = False
                        'clsConnSifei.writeLog("La Cadena Original calculada es diferente a la Cadena Original proporcionada " & _
                        '                     "por el Web Service para el Layout " & _
                        '                    System.IO.Path.GetFileName(pRutaLayout))
                    End If
                Else
                    valido = True
                End If
            Else
                'clsConnSifei.writeLog("No fue posible calcular la Cadena Original para el CFD del Layout " & _
                '                     System.IO.Path.GetFileName(pRutaLayout))
                valido = False
            End If
            Return valido
        Catch ex As Exception
            'clsConnSifei.writeLog("Ocurrió un error al validar el XML de " & System.IO.Path.GetFileName(pRutaLayout) & _
            '                     ": " & ex.Message)
            Return False
        End Try
    End Function
    Public Shared Function esXmlCFDIValido(ByVal xmlBase As XmlDocument, ByVal ruta As String) As Boolean
        Dim schemaSet As New XmlSchemaSet
        Dim settings As New XmlReaderSettings()
        Dim reader As XmlReader
        Dim nt As NameTable
        Dim nsmgr As XmlNamespaceManager
        Dim context As XmlParserContext
        Dim xml As String = ""
        Dim valido As Boolean = True
        Try
            Dim sw As StringWriter = New StringWriter()
            Dim xw As XmlTextWriter = New XmlTextWriter(sw)
            xmlBase.WriteTo(xw)
            xml = sw.ToString()
            schemaSet.Add("http://www.sat.gob.mx/cfd/3", XmlReader.Create(New StreamReader(ruta & "\CFDI\Xsd\cfdv3.xsd")))
            ''schemaSet.Add("<a href="http://www.<b style="color: black; background-color: rgb(255, 102, 255);">sat</b>.gob.mx/TimbreFiscalDigital">http://www.<b style="color: black; background-color: rgb(255, 102, 255);">sat</b>.gob.mx/TimbreFiscalDigital</a>", XmlReader.Create(New StreamReader("C:\Users\****\Desktop\TimbreFiscalDigital.xsd")))
            settings.Schemas = schemaSet
            settings.ValidationType = ValidationType.Schema
            nt = New NameTable()
            nsmgr = New XmlNamespaceManager(nt)
            nsmgr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema-instance")
            context = New XmlParserContext(Nothing, nsmgr, Nothing, XmlSpace.None)
            settings.ConformanceLevel = ConformanceLevel.Fragment
            reader = XmlReader.Create(New StringReader(xml), settings, context)
            While reader.Read
            End While
        Catch ex As Exception
            Throw New Exception("No se pudo validar el Comprobante por las siguientes causas: " & vbCrLf & ex.Message.ToString)
            valido = False
        Finally
            settings = Nothing
            reader = Nothing
            schemaSet = Nothing
            nt = Nothing
            nsmgr = Nothing
            context = Nothing
        End Try
        Return valido
    End Function
    ''' <summary>
    ''' Genera el nombre bajo el que se va a guardar el CFD a partir de los datos contenidos en el CFD y el Layout
    ''' </summary>
    ''' <param name="pRutaLayout">Ruta del Layout de donde se obtienen algunos datos para formar el nombre</param>
    ''' <param name="pXml">XmlDocument de donde se obtienen algunos datos para la generación del nombre</param>
    ''' <returns>
    ''' Cadena que representa el nombre del archivo en el formato: 'RFCEmisor_SerieFolio_Fecha(yyyyMMdd)_TipoCFD'
    ''' Cadena vacía si no se pudo obtener algún dato
    ''' </returns>
    ''' <remarks></remarks>
    Public Shared Function formaNombreCFD(ByVal pRutaLayout As String, ByVal pXml As XmlDocument) As String
        Try
            Dim nodeList As XmlNodeList
            Dim rfc As String = ""
            Dim serie As String = ""
            Dim folio As String = ""
            Dim fecha As String = ""
            Dim tipoCFD As String = ""
            nodeList = pXml.GetElementsByTagName("Comprobante")
            If (nodeList.Count = 1) Then
                If Not (nodeList(0).Attributes.ItemOf("serie") Is Nothing) Then
                    serie = nodeList(0).Attributes.GetNamedItem("serie").Value
                End If
                folio = nodeList(0).Attributes.GetNamedItem("folio").Value
                fecha = String.Format("{0:yyyyMMdd}", CDate(nodeList(0).Attributes.GetNamedItem("fecha").Value))
            End If
            nodeList = pXml.GetElementsByTagName("Emisor")
            If (nodeList.Count = 1) Then
                rfc = nodeList(0).Attributes.GetNamedItem("rfc").Value
            End If
            Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(pRutaLayout)
                MyReader.TextFieldType = FileIO.FieldType.Delimited
                MyReader.SetDelimiters("|")
                Dim currentRow As String()
                While Not MyReader.EndOfData
                    currentRow = MyReader.ReadFields()
                    If (currentRow(0) = "01") Then
                        Select Case currentRow(1).Trim.ToUpper()
                            Case "FA", "CP", "RH", "RA", "CA", "CR"
                                tipoCFD = currentRow(1).ToUpper()
                            Case Else
                                tipoCFD = ""
                        End Select
                        Exit While
                    End If
                End While
            End Using
            If (folio <> "" And fecha <> "" And rfc <> "" And tipoCFD <> "") Then
                Return rfc & "_" & serie & folio & "_" & fecha & "_" & tipoCFD
            Else
                'clsConnSifei.writeLog("No se encontraron datos necesarios para la formación del nombre del CFD para el Layout " & _
                '                     System.IO.Path.GetFileName(pRutaLayout))
                Return ""
            End If
        Catch ex As Exception
            'clsConnSifei.writeLog("Error al obtener los datos para la formación del nombre del CFD para el Layout " & _
            '                     System.IO.Path.GetFileName(pRutaLayout))
            Return ""
        End Try
    End Function
    ''' <summary>
    ''' Genera el nombre bajo el que se va a guardar el CFD a partir de los datos contenidos en el CFD y el Layout
    ''' </summary>
    ''' <param name="pRutaLayout">Ruta del Layout de donde se obtienen algunos datos para formar el nombre</param>
    ''' <param name="pXml">XmlDocument de donde se obtienen algunos datos para la generación del nombre</param>
    ''' <returns>
    ''' Cadena que representa el nombre del archivo en el formato: 'RFCEmisor_SerieFolio_Fecha(yyyyMMdd)_TipoCFD'
    ''' Cadena vacía si no se pudo obtener algún dato
    ''' </returns>
    ''' <remarks></remarks>
    Public Shared Function formaNombreCFDI(ByVal pRutaLayout As String, ByVal pXml As XmlDocument) As String
        Try
            Dim nodeList As XmlNodeList
            Dim rfc As String = ""
            Dim serie As String = ""
            Dim folio As String = ""
            Dim FolioInt As String = ""
            Dim fecha As String = ""
            Dim tipoCFD As String = ""
            Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(pRutaLayout)
                MyReader.TextFieldType = FileIO.FieldType.Delimited
                MyReader.SetDelimiters("|")
                Dim currentRow As String()
                While Not MyReader.EndOfData
                    currentRow = MyReader.ReadFields()
                    If (currentRow(0) = "01") Then
                        Select Case currentRow(1).Trim.ToUpper()
                            Case "FA", "CP", "RH", "RA", "CA", "CR", "RN", "RE"
                                tipoCFD = currentRow(1).ToUpper()
                            Case Else
                                tipoCFD = ""
                        End Select
                        Exit While
                    End If
                End While
            End Using
            If (tipoCFD = "RE") Then
                nodeList = pXml.GetElementsByTagName("retenciones:Retenciones")
                If (nodeList.Count = 1) Then
                    If Not (nodeList(0).Attributes.ItemOf("FolioInt") Is Nothing) Then
                        FolioInt = nodeList(0).Attributes.GetNamedItem("FolioInt").Value
                    End If
                    fecha = String.Format("{0:yyyyMMdd}", CDate(nodeList(0).Attributes.GetNamedItem("FechaExp").Value))
                End If
                nodeList = pXml.GetElementsByTagName("retenciones:Emisor")
                If (nodeList.Count = 1) Then
                    rfc = nodeList(0).Attributes.GetNamedItem("RFCEmisor").Value
                End If
                If (FolioInt <> "" And fecha <> "" And rfc <> "" And tipoCFD <> "") Then
                    Return rfc & "_" & FolioInt & "_" & fecha & "_" & tipoCFD
                Else
                    Dim ext As String = ".xml"
                    If (pRutaLayout.Contains(ext)) Then
                        Return rfc & "_" & FolioInt & "_" & fecha
                    Else
                        Return ""
                    End If
                End If
            Else
                nodeList = pXml.GetElementsByTagName("cfdi:Comprobante")
                If (nodeList.Count = 1) Then
                    If Not (nodeList(0).Attributes.ItemOf("serie") Is Nothing) Then
                        serie = nodeList(0).Attributes.GetNamedItem("serie").Value
                    End If
                    folio = nodeList(0).Attributes.GetNamedItem("folio").Value
                    fecha = String.Format("{0:yyyyMMdd}", CDate(nodeList(0).Attributes.GetNamedItem("fecha").Value))
                End If
                nodeList = pXml.GetElementsByTagName("cfdi:Emisor")
                If (nodeList.Count = 1) Then
                    rfc = nodeList(0).Attributes.GetNamedItem("rfc").Value
                End If

                If (folio <> "" And fecha <> "" And rfc <> "" And tipoCFD <> "") Then
                    Return rfc & "_" & serie & folio & "_" & fecha & "_" & tipoCFD
                Else
                    Dim ext As String = ".xml"
                    If (pRutaLayout.Contains(ext)) Then
                        Return rfc & "_" & serie & folio & "_" & fecha
                    Else
                        Return ""
                    End If
                End If
            End If

        Catch ex As Exception
            'clsConnSifei.writeLog("Error al obtener los datos para la formación del nombre del CFD para el Layout " & _
            '                     System.IO.Path.GetFileName(pRutaLayout))
            Return ""
        End Try
    End Function
    Public Shared Function formaNombreEnvio(ByVal pXml As XmlDocument) As String
        Try
            Dim nodeList As XmlNodeList
            Dim rfc As String = ""
            Dim serie As String = ""
            Dim folio As String = ""
            Dim fecha As String = ""
            Dim tipoCFD As String = ""
            nodeList = pXml.GetElementsByTagName("cfdi:Comprobante")
            If (nodeList.Count = 1) Then
                If Not (nodeList(0).Attributes.ItemOf("serie") Is Nothing) Then
                    serie = nodeList(0).Attributes.GetNamedItem("serie").Value
                End If
                folio = nodeList(0).Attributes.GetNamedItem("folio").Value
                fecha = String.Format("{0:yyyyMMdd}", CDate(nodeList(0).Attributes.GetNamedItem("fecha").Value))
            End If
            nodeList = pXml.GetElementsByTagName("cfdi:Emisor")
            If (nodeList.Count = 1) Then
                rfc = nodeList(0).Attributes.GetNamedItem("rfc").Value
            End If
            If (folio <> "" And fecha <> "" And rfc <> "") Then
                Return rfc & "_CFDi_" & serie & "_" & folio & "_" & fecha
            Else
                Return ""
            End If
        Catch ex As Exception
            Return ""
        End Try
    End Function

    Public Shared Function agregaAddenda(ByVal valor As Boolean) As XmlNode
        Try
            Dim pCfd As XmlDocument = New XmlDocument()
            Dim addenda As XmlNode
            Dim encabezado As XmlNode
            addenda = pCfd.CreateElement("cfdi", "Addenda", "http://www.sat.gob.mx/cfd/3")
            encabezado = pCfd.CreateElement("si", "Encabezado", "https://cfd.sifei.com.mx/publicar/")
            encabezado.Attributes.Append(pCfd.CreateAttribute("xsi:schemaLocation"))
            encabezado.Attributes("xsi:schemaLocation").Value = "https://cfd.sifei.com.mx/publicar/ https://cfd.sifei.com.mx/publicar/DocumentoSifei.xsd"
            encabezado.Attributes.Append(pCfd.CreateAttribute("MuestraIEPS"))
            If (valor = True) Then
                encabezado.Attributes("MuestraIEPS").Value = "SI"
            Else
                encabezado.Attributes("MuestraIEPS").Value = "NO"
            End If

            addenda.AppendChild(encabezado)


            Return addenda
        Catch ex As Exception
            Return Nothing
        End Try
    End Function
    Public Shared Function formaXmlBaseCFDI_Version3_X(ByVal comprobante As Comprobante, ByRef fechaCFD As DateTime, _
                                      ByRef pMsgError As String) As XmlDocument
        Thread.CurrentThread.CurrentCulture = New CultureInfo("es-MX", False)
        Try
            Dim memory_stream As New MemoryStream()
            Dim xmlNameSpace As XmlSerializerNamespaces = New XmlSerializerNamespaces()
            xmlNameSpace.Add("cfdi", "http://www.sat.gob.mx/cfd/3")
            'xmlNameSpace.Add("schemaLocation", "http://www.sat.gob.mx/cfd/3 cfdv3.xsd")
            xmlNameSpace.Add("xsi", "http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd")
            xmlNameSpace.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance")
            xmlNameSpace.Add("implocal", "http://www.sat.gob.mx/implocal")
            xmlNameSpace.Add("iedu", "http://www.sat.gob.mx/iedu")


            'SE AGREGAN NAMESPACES PARA IMPUESTOS LOCALES SI EXISTEN

            'FIN NAMESPACES IMPUESTOS LOCALES
            'Dim xmlTextWriter As XmlTextWriter = New XmlTextWriter("d:\cfdi.xml", Encoding.UTF8)
            Dim xmlTextWriter As XmlTextWriter = New XmlTextWriter(memory_stream, Encoding.UTF8)
            Dim preFactXml As XmlDocument = New XmlDocument()
            xmlTextWriter.Formatting = Formatting.Indented
            xmlTextWriter.Indentation = 4
            Dim xs As XmlSerializer = New XmlSerializer(GetType(Comprobante))

            xs.Serialize(xmlTextWriter, comprobante, xmlNameSpace)


            Dim stream_reader As New StreamReader(memory_stream)
            memory_stream.Seek(0, SeekOrigin.Begin)
            'Se carga el documento xml en 'preFactXml'
            preFactXml.LoadXml(stream_reader.ReadToEnd())
            xmlTextWriter.Close()
            Return preFactXml
        Catch ex As Exception
            'clsConnSifei.writeLog("Hubo un error al generar el XML CFDI: " & ex.Message)
            Return Nothing
        End Try

    End Function
    Public Function formaXmlBaseCFDI(ByVal comprobante As Comprobante, ByRef fechaCFD As DateTime, _
                                       ByRef pMsgError As String, ByVal impLocal As XmlElement) As XmlDocument
        Thread.CurrentThread.CurrentCulture = New CultureInfo("es-MX", False)
        Try
            If Not (impLocal Is Nothing) Then
                ReDim comprobante.Complemento.Any(0)
                comprobante.Complemento.Any(0) = impLocal
            End If
            Dim memory_stream As New MemoryStream()
            Dim xmlNameSpace As XmlSerializerNamespaces = New XmlSerializerNamespaces()
            xmlNameSpace.Add("cfdi", "http://www.sat.gob.mx/cfd/3")
            'xmlNameSpace.Add("schemaLocation", "http://www.sat.gob.mx/cfd/3 cfdv3.xsd")
            xmlNameSpace.Add("xsi", "http://www.sat.gob.mx/cfd/3 cfdv3.xsd")
            xmlNameSpace.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance")

            'SE AGREGAN NAMESPACES PARA IMPUESTOS LOCALES SI EXISTEN

            'FIN NAMESPACES IMPUESTOS LOCALES
            'Dim xmlTextWriter As XmlTextWriter = New XmlTextWriter("d:\cfdi.xml", Encoding.UTF8)
            Dim xmlTextWriter As XmlTextWriter = New XmlTextWriter(memory_stream, Encoding.UTF8)
            Dim preFactXml As XmlDocument = New XmlDocument()
            xmlTextWriter.Formatting = Formatting.Indented
            xmlTextWriter.Indentation = 4
            Dim xs As XmlSerializer = New XmlSerializer(GetType(Comprobante))

            xs.Serialize(xmlTextWriter, comprobante, xmlNameSpace)


            Dim stream_reader As New StreamReader(memory_stream)
            memory_stream.Seek(0, SeekOrigin.Begin)
            'Se carga el documento xml en 'preFactXml'
            preFactXml.LoadXml(stream_reader.ReadToEnd())
            xmlTextWriter.Close()
            Return preFactXml
        Catch ex As Exception
            'clsConnSifei.writeLog("Hubo un error al generar el XML CFDI: " & ex.Message)
            Return Nothing
        End Try

    End Function
    'Public Function formaXmlImpuestosLocales(ByVal impuestoLocal As ImpuestosLocales, _
    '                                    ByRef pMsgError As String) As XmlElement
    '    Thread.CurrentThread.CurrentCulture = New CultureInfo("es-MX", False)
    '    Try
    '        Dim memory_stream As New MemoryStream()
    '        Dim xmlNameSpace As XmlSerializerNamespaces = New XmlSerializerNamespaces()
    '        xmlNameSpace.Add("implocal", "http://www.sat.gob.mx/implocal")
    '        'FIN NAMESPACES IMPUESTOS LOCALES

    '        Dim xmlTextWriter As XmlTextWriter = New XmlTextWriter(memory_stream, Encoding.UTF8)
    '        Dim preFactXml As XmlDocument = New XmlDocument()
    '        xmlTextWriter.Formatting = Formatting.Indented
    '        xmlTextWriter.Indentation = 4
    '        Dim xs As XmlSerializer = New XmlSerializer(GetType(ImpuestosLocales))

    '        xs.Serialize(xmlTextWriter, impuestoLocal, xmlNameSpace)
    '        Dim stream_reader As New StreamReader(memory_stream)
    '        memory_stream.Seek(0, SeekOrigin.Begin)
    '        'Se carga el documento xml en 'preFactXml'
    '        preFactXml.LoadXml(stream_reader.ReadToEnd())
    '        xmlTextWriter.Close()
    '        Return preFactXml.DocumentElement
    '    Catch ex As Exception
    '        'clsConnSifei.writeLog("Hubo un error al generar el Impuesto local del  CFDI: " & ex.Message)
    '        Return Nothing
    '    End Try

    'End Function
    'Public Function formaXmlNomina(ByVal Nomina As Nomina.Nomina, _
    '                                    ByRef pMsgError As String) As XmlElement
    '    Thread.CurrentThread.CurrentCulture = New CultureInfo("es-MX", False)
    '    Try
    '        Dim memory_stream As New MemoryStream()
    '        Dim xmlNameSpace As XmlSerializerNamespaces = New XmlSerializerNamespaces()
    '        xmlNameSpace.Add("nomina", "http://www.sat.gob.mx/nomina")
    '        FIN NAMESPACES NOMINA

    '        Dim xmlTextWriter As XmlTextWriter = New XmlTextWriter(memory_stream, Encoding.UTF8)
    '        Dim preFactXml As XmlDocument = New XmlDocument()
    '        xmlTextWriter.Formatting = Formatting.Indented
    '        xmlTextWriter.Indentation = 4
    '        Dim xs As XmlSerializer = New XmlSerializer(GetType(Nomina.Nomina))

    '        xs.Serialize(xmlTextWriter, Nomina, xmlNameSpace)
    '        Dim stream_reader As New StreamReader(memory_stream)
    '        memory_stream.Seek(0, SeekOrigin.Begin)
    '        Se carga el documento xml en 'preFactXml'
    '        preFactXml.LoadXml(stream_reader.ReadToEnd())
    '        xmlTextWriter.Close()
    '        Return preFactXml.DocumentElement
    '    Catch ex As Exception
    '        Return Nothing
    '    End Try
    'End Function
    'Public Function formaXmlDetallista(ByVal Detallista As Detallista.detallista, _
    '                                   ByRef pMsgError As String) As XmlElement
    '    Thread.CurrentThread.CurrentCulture = New CultureInfo("es-MX", False)
    '    Try
    '        Dim memory_stream As New MemoryStream()
    '        Dim xmlNameSpace As XmlSerializerNamespaces = New XmlSerializerNamespaces()
    '        xmlNameSpace.Add("detallista", "http://www.sat.gob.mx/detallista")
    '        'FIN NAMESPACES DETALLISTA

    '        Dim xmlTextWriter As XmlTextWriter = New XmlTextWriter(memory_stream, Encoding.UTF8)
    '        Dim preFactXml As XmlDocument = New XmlDocument()
    '        xmlTextWriter.Formatting = Formatting.Indented
    '        xmlTextWriter.Indentation = 4
    '        Dim xs As XmlSerializer = New XmlSerializer(GetType(Detallista.detallista))

    '        xs.Serialize(xmlTextWriter, Detallista, xmlNameSpace)
    '        Dim stream_reader As New StreamReader(memory_stream)
    '        memory_stream.Seek(0, SeekOrigin.Begin)
    '        'Se carga el documento xml en 'preFactXml'
    '        preFactXml.LoadXml(stream_reader.ReadToEnd())
    '        xmlTextWriter.Close()
    '        Return preFactXml.DocumentElement
    '    Catch ex As Exception
    '        'clsConnSifei.writeLog("Hubo un error al generar el Impuesto local del  CFDI: " & ex.Message)
    '        Return Nothing
    '    End Try

    'End Function




    'Public Shared Function getConcentradoImpuestosCFD(ByVal tbConc As datasetNOTA.ConceptoDataTable) As DataTable
    '    Dim valIEPS As Double = 0D
    '    Dim tasaIEPS As Double = 0D
    '    Dim aplicaIVAExento As Boolean = False
    '    Dim aplicaIVATasa0 As Boolean = False
    '    Dim aplicaIVATasaNormal As Boolean = False
    '    Dim tasaIVA As Double = 0D
    '    Dim valIVA As Double = 0D

    '    For Each conc As datasetNOTA.ConceptoRow In tbConc
    '        If (conc.tasaIEPS > 0) Then
    '            valIEPS = valIEPS + conc.importeIEPS
    '            tasaIEPS = conc.tasaIEPS
    '        End If
    '        If (conc.tasaIVA.ToUpper() = "EXENTO") Then
    '            aplicaIVAExento = True
    '        Else
    '            If (conc.importeIVA > 0D) Then
    '                valIVA = valIVA + conc.importeIVA
    '                aplicaIVATasaNormal = True
    '                Try
    '                    tasaIVA = CDbl(conc.tasaIVA)
    '                Catch ex As Exception

    '                End Try
    '            Else
    '                aplicaIVATasa0 = True
    '            End If
    '        End If
    '        'If (conc.tasaIVA > 0) Then
    '        '    aplicaIVATasaNormal = True
    '        '    tasaIVA = conc.tasaIVA
    '        '    valIVA = valIVA + conc.importeIVA
    '        'Else
    '        '    aplicaIVATasa0 = True
    '        'End If
    '    Next

    '    Dim tbImpConc As DataTable = New DataTable("Impuestos")
    '    tbImpConc.Columns.Add("Impuesto", Type.GetType("System.String"))
    '    tbImpConc.Columns.Add("Tipo", Type.GetType("System.String"))
    '    tbImpConc.Columns.Add("Tasa", Type.GetType("System.Double"))
    '    tbImpConc.Columns.Add("Importe", Type.GetType("System.Double"))
    '    If (valIEPS > 0D) Then
    '        Dim rwImpCon As DataRow = tbImpConc.NewRow()
    '        rwImpCon("Impuesto") = "IEPS"
    '        rwImpCon("Tipo") = "T"
    '        rwImpCon("Tasa") = tasaIEPS
    '        rwImpCon("Importe") = valIEPS
    '        tbImpConc.Rows.Add(rwImpCon)
    '    End If
    '    If (aplicaIVATasa0) Then
    '        Dim rwImpCon As DataRow = tbImpConc.NewRow()
    '        rwImpCon("Impuesto") = "IVA"
    '        rwImpCon("Tipo") = "T"
    '        rwImpCon("Tasa") = 0D
    '        rwImpCon("Importe") = 0D
    '        tbImpConc.Rows.Add(rwImpCon)
    '    End If
    '    If (aplicaIVATasaNormal) Then
    '        Dim rwImpCon As DataRow = tbImpConc.NewRow()
    '        rwImpCon("Impuesto") = "IVA"
    '        rwImpCon("Tipo") = "T"
    '        rwImpCon("Tasa") = tasaIVA
    '        rwImpCon("Importe") = valIVA
    '        tbImpConc.Rows.Add(rwImpCon)
    '    End If
    '    Return tbImpConc
    'End Function
    Public Shared Sub escribeAtributoConReglasA20(ByVal pNombreAttrib As String, ByVal pCadena As String, _
                                           ByRef pXmlTextWriter As XmlTextWriter, ByVal pRequerido As Boolean)
        'Regla 1: No pipes en los campos
        pCadena = pCadena.Replace("|", "/")
        'Regla 5a: Reemplazar tabuladores, retornos de carro, y saltos de linea por espacios en blanco
        pCadena = pCadena.Replace(Chr(9), " ")      'TAB
        pCadena = pCadena.Replace(Chr(10), " ")     'SALTO DE LINEA
        pCadena = pCadena.Replace(Chr(13), " ")     'RETORNO DE CARRO
        'Regla 5b: Eliminar espacios en blanco al principio y al final
        pCadena = pCadena.Trim()
        'Regla 5c: Sustituir secuencia de espacios en blanco por uno solo
        Dim rsRegEx As System.Text.RegularExpressions.Regex
        rsRegEx = New System.Text.RegularExpressions.Regex("\s+")
        pCadena = rsRegEx.Replace(pCadena, " ").Trim()
        'xml_text_writer.WriteAttributeString("impuesto", row("Impuesto"))
        If (pCadena.Length > 0) Then
            pXmlTextWriter.WriteAttributeString(pNombreAttrib, pCadena)
        ElseIf (pRequerido) Then
            Throw New Exception("Falta elemento " & pNombreAttrib & " requerido para la formación del CFD")
        End If
    End Sub
    Public Shared Sub escribeAtributoConReglasA20CFDI(ByVal pNombreAttrib As String, ByRef pCadena As String, _
                                          ByVal pRequerido As Boolean, ByRef Resp As List(Of RespuestaPremium), _
                                          ByVal Linea As String, ByVal Columna As String)
        'Regla 1: No pipes en los campos
        pCadena = pCadena.Replace("|", "/")
        'Regla 5a: Reemplazar tabuladores, retornos de carro, y saltos de linea por espacios en blanco
        pCadena = pCadena.Replace(Chr(9), " ")      'TAB
        pCadena = pCadena.Replace(Chr(10), " ")     'SALTO DE LINEA
        pCadena = pCadena.Replace(Chr(13), " ")     'RETORNO DE CARRO
        'Regla 5b: Eliminar espacios en blanco al principio y al final
        pCadena = pCadena.Trim()
        'Regla 5c: Sustituir secuencia de espacios en blanco por uno solo
        Dim rsRegEx As System.Text.RegularExpressions.Regex
        rsRegEx = New System.Text.RegularExpressions.Regex("\s+")
        pCadena = rsRegEx.Replace(pCadena, " ").Trim()
        'xml_text_writers.WriteAttributeString("impuesto", row("Impuesto"))

        If (pRequerido And pCadena.Length = 0) Then
            ValidaCFDi.AgregaRespuesta(Linea, Columna, "Falta elemento " & pNombreAttrib & " requerido para la formación del CFD", Resp)
        End If
    End Sub
    'Public Shared Function obtenerSelloDigitalOpenSSL(ByVal cadOriginal As String, ByVal rutaLlavePrivada As String, _
    '                                           ByVal pwd As String, ByVal sellaMD5 As Boolean) As String
    '    Try
    '        Dim tipoDigest As String = ""
    '        If (sellaMD5) Then
    '            tipoDigest = "-md5"
    '        Else
    '            tipoDigest = "-sha1"
    '        End If
    '        Dim selloDigital As String = ""
    '        Dim passwordSeguro As System.Security.SecureString = New System.Security.SecureString()
    '        passwordSeguro.Clear()
    '        For Each c As Char In pwd.ToCharArray()
    '            passwordSeguro.AppendChar(c)
    '        Next
    '        'Dim llavePrivadaBytes As Byte() = System.IO.File.ReadAllBytes(rutaLlavePrivada)
    '        'Dim rsa As RSACryptoServiceProvider = opensslkey.DecodeEncryptedPrivateKeyInfo(llavePrivadaBytes, passwordSeguro)
    '        'Dim hasher As MD5CryptoServiceProvider = New MD5CryptoServiceProvider()
    '        'Dim bytesFirmados As Byte() = rsa.SignData(System.Text.Encoding.UTF8.GetBytes(cadOriginal), hasher)
    '        'Dim selloDigital As String = Convert.ToBase64String(bytesFirmados)
    '        'Return selloDigital
    '        Dim rutaPem As String = rutaLlavePrivada & ".pem"
    '        Dim rutaCadOrig As String = System.IO.Path.GetDirectoryName(rutaLlavePrivada) & "\cadena.txt"
    '        Dim rutaSelloBin As String = System.IO.Path.GetDirectoryName(rutaLlavePrivada) & "\SelloBin.txt"
    '        Dim rutaSello As String = System.IO.Path.GetDirectoryName(rutaLlavePrivada) & "\Sello.txt"
    '        If (System.IO.File.Exists(rutaCadOrig)) Then
    '            System.IO.File.Delete(rutaCadOrig)
    '        End If
    '        If (System.IO.File.Exists(rutaSelloBin)) Then
    '            System.IO.File.Delete(rutaSelloBin)
    '        End If
    '        If (System.IO.File.Exists(rutaSello)) Then
    '            System.IO.File.Delete(rutaSello)
    '        End If

    '        'Si no existe el archivo pem, generarlo
    '        If (Not System.IO.File.Exists(rutaPem)) Then
    '            Dim strCmd As String = ""
    '            strCmd = "openssl.exe pkcs8 -passin pass:" & pwd & _
    '                    " -inform DER -in " & Chr(34) & rutaLlavePrivada & Chr(34) & _
    '                    " -out " & Chr(34) & rutaPem & Chr(34)
    '            Shell(strCmd, , True, 5000)
    '        End If

    '        'Graba el archivo que contiene cadena original
    '        Dim utf8WithoutBom As New System.Text.UTF8Encoding(False)
    '        System.IO.File.WriteAllText(rutaCadOrig, cadOriginal, utf8WithoutBom)

    '        If (UtileriasBuzon.csUtilsArchivo.analizaArchivoDesocupadoMaxTiempo(rutaCadOrig)) Then
    '            If (System.IO.File.Exists(rutaPem)) Then
    '                'Se genera el archivo del sello binario
    '                Dim strCmd As String = ""
    '                'strCmd = "openssl.exe dgst -md5 -sign " & Chr(34) & rutaPem & Chr(34) & " d:\cadena.txt | openssl.exe enc -base64 -A > " & _
    '                '            "d:\sello.txt"
    '                strCmd = "openssl.exe dgst " & tipoDigest & " -sign " & Chr(34) & rutaPem & Chr(34) & _
    '                            " -out " & Chr(34) & rutaSelloBin & Chr(34) & " " & _
    '                            Chr(34) & rutaCadOrig & Chr(34)
    '                Shell(strCmd, , True, 5000)

    '                If (UtileriasBuzon.csUtilsArchivo.analizaArchivoDesocupadoMaxTiempo(rutaSelloBin)) Then
    '                    'Se genera el archivo del sello digital
    '                    strCmd = "openssl enc -base64 -in " & Chr(34) & rutaSelloBin & Chr(34) & _
    '                            " -out " & Chr(34) & rutaSello & Chr(34)
    '                    Shell(strCmd, , True, 5000)
    '                    If (UtileriasBuzon.csUtilsArchivo.analizaArchivoDesocupadoMaxTiempo(rutaSello)) Then
    '                        Using reader As StreamReader = New StreamReader(rutaSello)
    '                            selloDigital = reader.ReadToEnd()
    '                            selloDigital = selloDigital.Replace(Chr(10), "")
    '                            selloDigital = selloDigital.Replace(Chr(13), "")
    '                        End Using
    '                    End If
    '                End If
    '            End If
    '        End If

    '        Return selloDigital
    '    Catch ex As Exception
    '        'clsConnSifei.writeLog("Hubo un error al generar el sello: " & ex.Message)
    '        Return ""
    '    End Try
    'End Function
    ''' <summary>
    ''' Analiza en la respuesta del Web Service Sifei si éste encontró errores al procesar el Xml Original
    ''' </summary>
    ''' <param name="pXmlDoc">XmlDocument. Representa la respuesta del Web Service Sifei</param>
    ''' <returns>String:
    ''' Cadena vacía si no encontró errores.
    ''' Cadena con el contenido de los errores que encontró en <c>pXmlDoc</c>
    ''' Cadena con el contenido de la excepción si ésta ocurre.</returns>
    ''' <remarks>Si regresa una cadena vacía, significa que no se encontró ningun error en el CFD</remarks>
    Public Shared Function getErroresEnCFD(ByVal pXmlDoc As XmlDocument) As String
        Try
            Dim errores As String = ""
            Dim nodeList As XmlNodeList
            'Obtenemos la lista de los nodos "Errores" si es que hubo
            nodeList = pXmlDoc.GetElementsByTagName("Errores")

            If (nodeList.Count > 0) Then
                For Each node As XmlNode In nodeList
                    errores = errores & node.Attributes.GetNamedItem("numError").Value & vbCrLf
                Next
            End If
            Return errores
        Catch ex As Exception
            Return ex.Message
        End Try
    End Function

End Class
